﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureFloorHoleGraphicsElementShapeBehavior.h"
#include "StructureInstanceGrepUtil.h"

#include "IInstance.h"
#include "IGraphicsElementShape.h"
#include "IDocument.h"
#include "IElementPosition.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IOpeningGraphicsElementShapeComponent.h"
#include "IBaseGraphicsElementShapeComponent.h"
#include "DbObjectUtils.h"
#include "GraphicsNodeUtils.h"
#include "IGraphicsBRepBody.h"
#include "IGraphicsStyleManager.h"
#include "IElementModelShape.h"
#include "IElementBasicInformation.h"

#include "GcmpElementModelingOperator.h"

#include "IGeometryRelationshipComponent.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    OwnerPtr<IGraphicsBRepBody>  GetGRepBody(const IDocument* pDoc, const IGraphicsElementShape* pGRep)
    {
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc无效指针",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGRep, L"pGRep无效指针",L"GDMPLab",L"2024-03-30");
        std::vector<const IGraphicsBRepBody*> gbodies;
        std::vector<Matrix4d> transforms;
        std::vector<std::vector<const IGraphicsNode*>> paths;
        GraphicsNodeUtils::CollectBRepBodies(pDoc, pGRep, &gbodies, &transforms, &paths);

        //找出实体Body，默认墙只有一个实体，排除Shell Body，比如墙的中心面，族中作为项目参照的参照平面等
        int solidBodyIndex = -1;
        FOR_EACH_INDEX(gbodyIndex, gbodies)
        {
            if (!gbodies[gbodyIndex]->IsShell())
            {
                solidBodyIndex = gbodyIndex;
                break;
            }
        }

        if (solidBodyIndex == -1)
            return nullptr;

        OwnerPtr<IGraphicsBRepBody> opGBody = TransferOwnershipCast<IGraphicsBRepBody>(gbodies[solidBodyIndex]->Clone());
        bool transformCode = opGBody->Transform(transforms[solidBodyIndex]);
        if (!transformCode)
        {
            return nullptr;
        }

        return opGBody;
    }
}

DBOBJECT_DATA_DEFINE(StructureFloorHoleGraphicsElementShapeBehavior)
{
    m_pOwnerElement = nullptr;
}

StructureFloorHoleGraphicsElementShapeBehavior::StructureFloorHoleGraphicsElementShapeBehavior(IElement *pInstance)
{
    m_pOwnerElement = pInstance;
}

bool StructureFloorHoleGraphicsElementShapeBehavior::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    return true;
}

IInstance* StructureFloorHoleGraphicsElementShapeBehavior::GetOwnerInstance() const
{
    return quick_cast<IInstance>(m_pOwnerElement);
}

NdbObject* StructureFloorHoleGraphicsElementShapeBehavior::GetTopOwnerObject() const
{
    return nullptr;
}

void StructureFloorHoleGraphicsElementShapeBehavior::ReportInputDataIds(std::vector<RegenDataId>& oInputDataIds) const
{
    const IInstance* pInstance = GetOwnerInstance();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInstance->GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const IInstance* pHostInstance = quick_cast<IInstance>(pDoc->GetElement(pInstance->GetHostInstanceId()));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pHostInstance, L"pHostInstance为空",L"GDMPLab",L"2024-03-30");

    const IElementModelShape* pGrepBehavior = pHostInstance->GetElementModelShape();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGrepBehavior, L"构件IGraphicsElementShapeBehavior为空",L"GDMPLab",L"2024-03-30");

    oInputDataIds.push_back(pGrepBehavior->GetGraphicsElementShapeRdId());
}

OwnerPtr<IGraphicsElementShape> StructureFloorHoleGraphicsElementShapeBehavior::Customize(OwnerPtr<IGraphicsElementShape> opGRep) const
{
    IInstance* pIInstance = GetOwnerInstance();
    DBG_WARN_AND_RETURN_UNLESS(pIInstance, opGRep, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pIInstance->GetDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, opGRep, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const IInstance* pHostInstance = quick_cast<IInstance>(pDoc->GetElement(pIInstance->GetHostInstanceId()));
    DBG_WARN_AND_RETURN_UNLESS(pHostInstance, opGRep, L"pHostInstance为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IGraphicsElementShape> upGRep; // Base GRep

    // 扣减体根节点
    upGRep = IGraphicsElementShape::Create(opGRep->GetRenderLayer());

    OwnerPtr<IGraphicsElementShape> opHostsGRep;
    {
        const IBaseGraphicsElementShapeComponent* pHostInstanceShapeComponent = pHostInstance->GetBaseGraphicsElementShapeComponent();
        DBG_WARN_AND_RETURN_UNLESS(pHostInstanceShapeComponent, opGRep, L"pHostInstanceShapeComponent为空",L"GDMPLab",L"2024-03-30");

        const IGraphicsElementShape* pHostBaseGRep = pHostInstanceShapeComponent->GetBaseGraphicsElementShape();
        DBG_WARN_AND_RETURN_UNLESS(pHostBaseGRep, opGRep, L"pHostGRep为空",L"GDMPLab",L"2024-03-30");

        if (pHostInstance->GetBasicInformation()->GetCategoryUid().HasSameValue(BuiltInCategoryUniIdentities::BICU_STRUCTURE_FLOOR))
        {
            opHostsGRep = StructureInstanceGrepUtil::GenerateFloorGrepFromBaseGrep(pHostInstance, pHostBaseGRep);
        }
    }

    OwnerPtr<IGraphicsElementShape> opClonedCutterGRep;
    {
        const IGeometryRelationshipComponent* pGeometryRepCpt = pIInstance->GetGeometryRelationshipComponent();
        DBG_WARN_AND_RETURN_UNLESS(pGeometryRepCpt != nullptr, opGRep,L"无效的指针",L"GDMPLab",L"2024-03-30");
        const IOpeningGraphicsElementShapeComponent* pCutterGRepComponent = pGeometryRepCpt->GetOpeningGraphicsElementShapeComponent();
        DBG_WARN_AND_RETURN_UNLESS(pCutterGRepComponent != nullptr, opGRep,L"无效的指针",L"GDMPLab",L"2024-03-30");
        const IGraphicsElementShape* pCutterGRep = pCutterGRepComponent->GetOpeningGraphicsElementShape();
        DBG_WARN_AND_RETURN_UNLESS(pCutterGRep, opGRep, L"pCutterGRep为空",L"GDMPLab",L"2024-03-30");
        opClonedCutterGRep = TransferOwnershipCast<IGraphicsElementShape>(pCutterGRep->Clone());
        StructureInstanceGrepUtil::TransformGRep(opClonedCutterGRep.get(), pIInstance);
    }

    //
    OwnerPtr<IGraphicsBRepBody> opIntersectBody;
    opIntersectBody = CreateBoolIntersectOperation(pIInstance, TransferOwnership(opClonedCutterGRep), 
                                                   TransferOwnership(opHostsGRep));
    if (opIntersectBody)
    {
        upGRep->AddChild(TransferOwnership(opIntersectBody));
        upGRep->SetElementId(pIInstance->GetElementId());
        upGRep->SetVisibility(GraphicsNodeVisibility::Always);
        upGRep->SetGraphicsStyleId(pDoc->GetGraphicsStyleManager()->GetGraphicsStyleIdByCategoryUid(pIInstance->GetBasicInformation()->GetCategoryUid()));
        return upGRep;
    }

    return opGRep;
}

OwnerPtr<IGraphicsBRepBody> StructureFloorHoleGraphicsElementShapeBehavior::CreateBoolIntersectOperation
(   
    IInstance* pIInstance, 
    OwnerPtr<IGraphicsElementShape> opHostsGRep,
    OwnerPtr<IGraphicsElementShape> opCutterGRep
)const
{
    return GcmpElementModelingOperator::CreateBoolBodyOperation(pIInstance, opHostsGRep.get(), opCutterGRep.get(),
                                                              gcmp::BooleanOperationTypes::Intersect);
}
